package com.bwie.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bwie.es.EsCouponRecord;
import com.bwie.mapper.TbCouponRecordMapper;
import com.bwie.pojo.TbCoupon;
import com.bwie.pojo.TbCouponRecord;
import com.bwie.service.TbCouponService;
import com.bwie.mapper.TbCouponMapper;
import com.bwie.utils.R;
import com.bwie.utils.TokenUtils;
import com.bwie.vo.PageInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.lucene.queryparser.xml.builders.BooleanQueryBuilder;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.support.Acknowledgment;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

/**
* @author Lenovo
* @description 针对表【tb_coupon(优惠券表)】的数据库操作Service实现
* @createDate 2025-07-09 20:23:04
*/
@Service
@Slf4j
public class TbCouponServiceImpl extends ServiceImpl<TbCouponMapper, TbCoupon>
    implements TbCouponService{

    @Autowired
    TbCouponMapper tbCouponMapper;
    @Autowired
    HttpServletRequest request;
    @Autowired
    TbCouponRecordMapper tbCouponRecordMapper;
    @Autowired
    KafkaTemplate kafkaTemplate;
    @Autowired
    ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Override
    public R getCouponList(PageInfoVo pageInfoVo) {
        Page<TbCoupon> page = new Page<>(pageInfoVo.getPageNum(), pageInfoVo.getPageSize());

        LambdaQueryWrapper<TbCoupon> wrapper = new LambdaQueryWrapper<>();
        if(StringUtils.isNotEmpty(pageInfoVo.getKeyWord())){
            wrapper.like(TbCoupon::getCouponName,pageInfoVo.getKeyWord());
        }
        wrapper.orderByDesc(TbCoupon::getCreateTime);

        Page<TbCoupon> tbCouponPage = tbCouponMapper.selectPage(page, wrapper);
        return R.ok(tbCouponPage);
    }

    @Override
    public R addCoupon(TbCoupon tbCoupon) {
        String token = request.getHeader("token");
        if(token == null){
            return R.error(404,"请先登录");
        }

        TbCoupon coupon = tbCouponMapper.selectOne(new LambdaQueryWrapper<TbCoupon>().eq(TbCoupon::getCouponName, tbCoupon.getCouponName()));
        if(coupon != null){
            return R.error(500,"该优惠券已存在");
        }

        String userName = TokenUtils.getUserName(token);

        //使用时间
        if(tbCoupon.getUseDay()==2){
            if(tbCoupon.getUseTimes() != null && tbCoupon.getUseTimes().size() == 2){
                try {
                    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    List<String> useTimes = tbCoupon.getUseTimes();
                    tbCoupon.setBeginTime(format.parse(useTimes.get(0)));
                    tbCoupon.setEndTime(format.parse(useTimes.get(1)));
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            }
        }

        //领取时间
        if(tbCoupon.getGetTime() == 1){
            if(tbCoupon.getGetTimes()!=null && tbCoupon.getGetTimes().size()==2){
                try {
                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    List<String> getTimes = tbCoupon.getGetTimes();
                    tbCoupon.setGetBeginTime(simpleDateFormat.parse(getTimes.get(0)));
                    tbCoupon.setGetEndTime(simpleDateFormat.parse(getTimes.get(1)));
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            }
        }

        tbCoupon.setCreateBy(userName);
        tbCoupon.setCreateTime(new Date());

        tbCouponMapper.insert(tbCoupon);
        return R.ok();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R claimCoupon(Integer couponId) {
        String token = request.getHeader("token");
        if(token == null){
            return R.error(404,"请先登录");
        }
        Integer userId = TokenUtils.getUserId(token);
        String userName = TokenUtils.getUserName(token);

        TbCoupon tbCoupon = tbCouponMapper.selectById(couponId);
        if(tbCoupon == null){
            return R.error(404,"优惠券不存在");
        }

        //领取时
        if(tbCoupon.getLimitFlag() == 1){
            if(tbCoupon.getLimitNum() == null && tbCoupon.getLimitNum() ==0){
                return R.error(500,"优惠券已经被领光了");
            }

            tbCoupon.setLimitNum(tbCoupon.getLimitNum()-1);
            tbCouponMapper.updateById(tbCoupon);
        }

        if(tbCoupon.getGetTime() == 1){
            long timeMillis = System.currentTimeMillis();
            if(timeMillis<tbCoupon.getBeginTime().getTime()){
                return R.error(500,"领取时间还未到，请等待");
            }
            if(timeMillis>tbCoupon.getEndTime().getTime()){
                return R.error(500,"领取时间已经结束了，请下次再来");
            }
        }

        TbCouponRecord tbCouponRecord = new TbCouponRecord();
        tbCouponRecord.setCouponId(couponId);
        tbCouponRecord.setUserId(userId);
        //使用时间、生效时间、过期时间未加

        tbCouponRecord.setCreateBy(userName);
        tbCouponRecord.setCreateTime(new Date());

        //发送kafka消息
        log.info("发送kafka消息");
        kafkaTemplate.send("topic-claim",JSON.toJSONString(tbCouponRecord));
//        tbCouponRecordMapper.insert(tbCouponRecord);

        return R.ok();
    }

    @Override
    public R getCouponRecordList(PageInfoVo pageInfoVo) {
        //构造分页参数
        Integer pageNum = 0;
        if(pageInfoVo.getPageNum() > 0){
            pageNum = pageInfoVo.getPageNum() - 1;
        }
        PageRequest pageRequest = PageRequest.of(pageNum, pageInfoVo.getPageSize());
        //创建查询条件
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        if(StringUtils.isNotEmpty(pageInfoVo.getKeyWord())){
            boolQueryBuilder.must(QueryBuilders.matchQuery("couponName",pageInfoVo.getKeyWord()));
        }
        //高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("couponName").preTags("<font color='red'>").postTags("</font>");
        //排序
        FieldSortBuilder sortBuilder = SortBuilders.fieldSort("createTime").order(SortOrder.DESC);

        //开始查询
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        nativeSearchQueryBuilder.withPageable(pageRequest)
                .withQuery(boolQueryBuilder)
                .withHighlightBuilder(highlightBuilder)
                .withSort(sortBuilder);
        SearchHits<EsCouponRecord> searchHits = elasticsearchRestTemplate.search(nativeSearchQueryBuilder.build(), EsCouponRecord.class);

        //查询结果
        long total = searchHits.getTotalHits();
        ArrayList<EsCouponRecord> records = new ArrayList<>();

        for (SearchHit<EsCouponRecord> searchHit : searchHits.getSearchHits()) {
            EsCouponRecord esCouponRecord = searchHit.getContent();

            List<String> couponName = searchHit.getHighlightField("couponName");
            if(couponName != null && couponName.size() > 0){
                esCouponRecord.setCouponName(couponName.get(0));
            }

            records.add(esCouponRecord);
        }

        HashMap<String, Object> map = new HashMap<>();
        map.put("records",records);
        map.put("total",total);
        return R.ok(map);
    }

    @KafkaListener(topics = "topic-claim")
    public void recvClaimCoupon(String msg, Acknowledgment acknowledgment){
        log.info("接收kafka消息："+msg);
        TbCouponRecord tbCouponRecord = JSON.parseObject(msg, TbCouponRecord.class);

        tbCouponRecordMapper.insert(tbCouponRecord);

        IndexOperations indexOps = elasticsearchRestTemplate.indexOps(EsCouponRecord.class);
        boolean exists = indexOps.exists();
        if(!exists){
            indexOps.create();

            Document mapping = indexOps.createMapping();
            indexOps.putMapping(mapping);
        }

        EsCouponRecord esCouponRecord = BeanUtil.toBean(tbCouponRecord, EsCouponRecord.class);
        elasticsearchRestTemplate.save(esCouponRecord);

        //手动确认消息
        acknowledgment.acknowledge();
    }

    @Scheduled(cron = "0 0/1 * * * ?")
    public void loadDataToEs(){
        log.info("开始执行定时任务");

        IndexOperations indexOps = elasticsearchRestTemplate.indexOps(EsCouponRecord.class);
        boolean exists = indexOps.exists();
        if(!exists){
            indexOps.create();

            Document mapping = indexOps.createMapping();
            indexOps.putMapping(mapping);
        }

        List<TbCouponRecord> tbCouponRecords = tbCouponRecordMapper.getCouponRecord();
        for (TbCouponRecord tbCouponRecord : tbCouponRecords) {
            EsCouponRecord esCouponRecord = BeanUtil.toBean(tbCouponRecord, EsCouponRecord.class);
            elasticsearchRestTemplate.save(esCouponRecord);
        }

        log.info("定时任务执行完毕");
    }
}




